package org.tinygroup.earthworm;

import java.util.Map;

import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;

public class EarthWorm {
	private static final String ROOT_SPAN_ID = "1";
	private static final String MAL_ROOT_SPAN_ID = "1";
	private static LogService logService = LogService.getInstance();
	private static Logger LOGGER = LoggerFactory.getLogger(EarthWorm.class);

	public static void startTrace(String traceId, String traceName) {
		startTrace(traceId, (String) null, traceName);
	}

	public static void startTrace(String traceId, String spanId, String traceName) {
		if (traceName != null) {
			traceId = EarthWormHelper.trim(traceId);
			if (!EarthWormHelper.validTraceId(traceId)) {
				traceId = EarthWormHelper.generate();
				spanId = ROOT_SPAN_ID;
			} else if (!EarthWormHelper.validSpanId(spanId)) {
				spanId = ROOT_SPAN_ID;
			}

			RpcContext ctx = RpcContext.get();
			if (ctx != null && ctx.traceId != null) {
				if (ctx.traceId.equals(traceId) && traceName.equals(ctx.traceName)) {
					return;
				}
				endTrace();
			}
			try {
				ctx = new RpcContext(traceId, spanId);
				RpcContext.set(ctx);
				ctx.startTrace(traceName);
			} catch (Throwable t) {
				LOGGER.errorMessage("startTrace exception,traceId:{},spanId:{},traceName:{}", t, traceId, spanId,
						traceName);
			}
			logService.logStage("starttrace");
		} else {
			LOGGER.infoMessage("trace name为空，不开启trace");
		}
	}

	public static void endTrace() {
		endTrace((String) null, 0);
	}

	public static void endTrace(String resultCode, int type) {
		try {
			RpcContext re = RpcContext.get();
			if (null == re) {
				return;
			}
			while (null != re.parent) {
				re = re.parent;
			}
			re.endTrace();
		} finally {
			clearRpcContext();
		}
		logService.logStage("endtrace");
	}

	public static void startRpc(String tag) {
		RpcContext re = RpcContext.get();
		RpcContext childCtx;
		if (null == re) {
			childCtx = new RpcContext(EarthWormHelper.generate(), MAL_ROOT_SPAN_ID);
		} else {
			childCtx = re.createChildRpc();
		}

		RpcContext.set(childCtx);
		childCtx.startRpc(tag);
		logService.logStage("startrpc");
	}

	public static void startLocal(String tag) {
		RpcContext re = RpcContext.get();
		if (null == re) {
			return;
		}

		RpcContext cloneCtx = re.cloneInstance();
		RpcContext.set(cloneCtx);
		cloneCtx.startLocal(tag);
		logService.logStage("startlocal");
	}

	public static void endLocal() {
		RpcContext re = RpcContext.get();
		if (null == re) {

			return;
		}
		re.endLocal();
		logService.logStage("endlocal");
	}

	public static void rpcClientSend() {
		RpcContext re = RpcContext.get();
		if (null == re) {
			return;
		}
		re.rpcClientSend();
		logService.logStage("rpcClientSend");
	}
	public static void rpcClientRecv(){
		rpcClientRecv(RpcContext.RPC_STAT_SUCESS);
	}

	public static void rpcClientRecv(int stat) {
		RpcContext re = RpcContext.get();
		if (null == re) {
			return;
		}
		re.endRpc(stat);
		RpcContext.set(re.parent);
		logService.logStage("rpcClientRecv");

	}

	public static void rpcServerRecv(String tag) {
		createContextIfNotExists(true).rpcServerRecv(tag);
		logService.logStage("rpcServerRecv");
	}

	public static void rpcServerSend() {
		try {
			RpcContext re = RpcContext.get();
			if (re != null) {
				re.rpcServerSend();

			}
			logService.logStage("rpcServerSend");
		} finally {
			clearRpcContext();
		}

	}

	public static String getTraceId() {
		RpcContext ctx = RpcContext.get();
		return null == ctx ? null : ctx.traceId;
	}

	public static String getSpanId() {
		RpcContext ctx = RpcContext.get();
		return null == ctx ? null : ctx.spanId;
	}

	public static String getLocalId() {
		RpcContext ctx = RpcContext.get();
		return null == ctx ? "" : ctx.localId;
	}

	public static Object currentRpcContext() {
		RpcContext re = RpcContext.get();
		if (null != re) {
			return re.toMap();
		}
		return null;
	}

	public static RpcContext getRpcContext() {
		return RpcContext.get();
	}

	public static RpcContext createRootRpcContext(String traceId, String rpcId) {
		if (traceId == null) {
			traceId = EarthWormHelper.generate();
		}

		if (rpcId == null) {
			rpcId = MAL_ROOT_SPAN_ID;
		}

		return new RpcContext(traceId, rpcId);
	}

	public static RpcContext createRpcContextFromMap(Map<String, String> map) {
		return RpcContext.fromMap(map);
	}

	static final RpcContext createContextIfNotExists(boolean setToThreadLocal) {
		RpcContext ctx = RpcContext.get();
		if (null == ctx) {
			RpcContext newCtx = new RpcContext(EarthWormHelper.generate(), MAL_ROOT_SPAN_ID);
			if (setToThreadLocal) {
				RpcContext.set(newCtx);
			}
			return newCtx;
		} else {
			return ctx;
		}
	}

	public static void setRpcContext(Object rpcCtx) {
		try {
			RpcContext re = null;
			if (rpcCtx instanceof Map) {
				re = RpcContext.fromMap((Map) rpcCtx);
			} else if (rpcCtx instanceof RpcContext) {
				re = (RpcContext) rpcCtx;
			}

			RpcContext.set(re);
		} catch (Throwable t) {
			LOGGER.errorMessage("set RpcContext exception", t);
		}
	}

	public static void setRpcContext(RpcContext context) {
		RpcContext.set(context);
	}

	private static void clearRpcContext() {
		RpcContext.set(null);
		logService.clear();
	}

}
